{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Before reading, make sure to review\n",
    "\n",
    "- [MVC prgramming](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)\n",
    "- [Backbone.js](https://www.codeschool.com/courses/anatomy-of-backbonejs)\n",
    "- [The widget IPEP](https://github.com/ipython/ipython/wiki/IPEP-23%3A-Backbone.js-Widgets)\n",
    "- [The original widget PR discussion](https://github.com/ipython/ipython/pull/4374)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from __future__ import print_function # For py 2.7 compat\n",
    "\n",
    "import ipywidgets as widgets # Widget definitions\n",
    "from IPython.display import display # Used to display widgets in the notebook\n",
    "from traitlets import Unicode # Used to declare attributes of our widget"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Abstract"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook implements a custom date picker widget,\n",
    "in order to demonstrate the widget creation process.\n",
    "\n",
    "To create a custom widget, both Python and JavaScript code is required."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Section 1 - Basics"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Python"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When starting a project like this, it is often easiest to make a simple base implementation,\n",
    "to verify that the underlying framework is working as expected.\n",
    "To start, we will create an empty widget and make sure that it can be rendered.\n",
    "The first step is to define the widget in Python."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "class DateWidget(widgets.DOMWidget):\n",
    "    _view_name = Unicode('DatePickerView').tag(sync=True)\n",
    "    _view_module = Unicode('datepicker').tag(sync=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Our widget inherits from `widgets.DOMWidget` since it is intended that it will be displayed in the notebook directly.\n",
    "The `_view_name` trait is special; the widget framework will read the `_view_name` trait to determine what Backbone view the widget is associated with.\n",
    "**Using `sync=True` is very important** because it tells the widget framework that that specific traitlet should be synced between the front- and back-ends."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## JavaScript"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the IPython notebook [require.js](http://requirejs.org/) is used to load JavaScript dependencies.\n",
    "All Jupyter widget code depends on `jupyter-js-widgets`, where the base widget model and base view are defined.\n",
    "We use require.js to load this file:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "\n",
       "define('datepicker', [\"jupyter-js-widgets\"], function(widgets) {\n",
       "\n",
       "});"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%%javascript\n",
    "\n",
    "define('datepicker', [\"jupyter-js-widgets\"], function(widgets) {\n",
    "\n",
    "});"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we need to define a view that can be used to represent the model.\n",
    "To do this, the `DOMWidgetView` is extended.\n",
    "**A render function must be defined**.\n",
    "The render function is used to render a widget view instance to the DOM.\n",
    "For now, the render function renders a div that contains the text *Hello World!*\n",
    "Lastly, the view needs to be registered with the widget manager, for which we need to load another module.\n",
    "\n",
    "**Final JavaScript code below:**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "requirejs.undef('datepicker');\n",
       "\n",
       "define('datepicker', [\"jupyter-js-widgets\"], function(widgets) {\n",
       "    \n",
       "    // Define the DatePickerView\n",
       "    var DatePickerView = widgets.DOMWidgetView.extend({\n",
       "        render: function() { this.$el.text('Hello World!'); },\n",
       "    });\n",
       "    \n",
       "    return {\n",
       "        DatePickerView: DatePickerView\n",
       "    };\n",
       "});"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%%javascript\n",
    "requirejs.undef('datepicker');\n",
    "\n",
    "define('datepicker', [\"jupyter-js-widgets\"], function(widgets) {\n",
    "    \n",
    "    // Define the DatePickerView\n",
    "    var DatePickerView = widgets.DOMWidgetView.extend({\n",
    "        render: function() { this.$el.text('Hello World!'); },\n",
    "    });\n",
    "    \n",
    "    return {\n",
    "        DatePickerView: DatePickerView\n",
    "    };\n",
    "});"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Test"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To test what we have so far, create the widget, just like you would the builtin widgets:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/html": [
       "<img src= class=\"jupyter-widget\">\n",
       "<script type=\"application/vnd.jupyter-embedded-widgets\">[{},{\"_view_name\":\"DatePickerView\",\"_view_module\":\"datepicker\",\"layout\":\"IPY_MODEL_63fd4d6d070148018e4867d75a442324\",\"_model_name\":\"DOMWidgetModel\"}]</script>"
      ]
     },
     "metadata": {
      "isWidgetSnapshot": true
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "DateWidget()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Section 2 - Something useful"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Python"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the last section we created a simple widget that displayed *Hello World!*\n",
    "To make an actual date widget, we need to add a property that will be synced between the Python model and the JavaScript model.\n",
    "The new attribute must be a traitlet, so the widget machinery can handle it.\n",
    "The traitlet must be constructed with a `sync=True` keyword argument, to tell the widget machinery knows to synchronize it with the front-end.\n",
    "Adding this to the code from the last section:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "class DateWidget(widgets.DOMWidget):\n",
    "    _view_name = Unicode('DatePickerView').tag(sync=True)\n",
    "    _view_module = Unicode('datepicker').tag(sync=True)\n",
    "    value = Unicode().tag(sync=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## JavaScript"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the JavaScript, there is no need to define counterparts to the traitlets.\n",
    "When the JavaScript model is created for the first time,\n",
    "it copies all of the traitlet `sync=True` attributes from the Python model.\n",
    "We need to replace *Hello World!* with an actual HTML date picker widget."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "requirejs.undef('datepicker');\n",
       "\n",
       "define('datepicker', [\"jupyter-js-widgets\"], function(widgets) {\n",
       "     \n",
       "    // Define the DatePickerView\n",
       "    var DatePickerView = widgets.DOMWidgetView.extend({\n",
       "        render: function() {\n",
       "            \n",
       "            // Create the date picker control.\n",
       "            this.$date = $('<input />')\n",
       "                .attr('type', 'date')\n",
       "                .appendTo(this.$el);\n",
       "        },\n",
       "    });\n",
       "    \n",
       "    return {\n",
       "        DatePickerView: DatePickerView\n",
       "    };\n",
       "});"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%%javascript\n",
    "requirejs.undef('datepicker');\n",
    "\n",
    "define('datepicker', [\"jupyter-js-widgets\"], function(widgets) {\n",
    "     \n",
    "    // Define the DatePickerView\n",
    "    var DatePickerView = widgets.DOMWidgetView.extend({\n",
    "        render: function() {\n",
    "            \n",
    "            // Create the date picker control.\n",
    "            this.$date = $('<input />')\n",
    "                .attr('type', 'date')\n",
    "                .appendTo(this.$el);\n",
    "        },\n",
    "    });\n",
    "    \n",
    "    return {\n",
    "        DatePickerView: DatePickerView\n",
    "    };\n",
    "});"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In order to get the HTML date picker to update itself with the value set in the back-end, we need to implement an `update()` method."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "requirejs.undef('datepicker');\n",
       "\n",
       "define('datepicker', [\"jupyter-js-widgets\"], function(widgets) {\n",
       "    \n",
       "    // Define the DatePickerView\n",
       "    var DatePickerView = widgets.DOMWidgetView.extend({\n",
       "        render: function() {\n",
       "            \n",
       "            // Create the date picker control.\n",
       "            this.$date = $('<input />')\n",
       "                .attr('type', 'date')\n",
       "                .appendTo(this.$el);\n",
       "        },\n",
       "        \n",
       "        update: function() {\n",
       "            \n",
       "            // Set the value of the date control and then call base.\n",
       "            this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
       "            return DatePickerView.__super__.update.apply(this);\n",
       "        },\n",
       "    });\n",
       "    \n",
       "    return {\n",
       "        DatePickerView: DatePickerView\n",
       "    };\n",
       "});"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%%javascript\n",
    "requirejs.undef('datepicker');\n",
    "\n",
    "define('datepicker', [\"jupyter-js-widgets\"], function(widgets) {\n",
    "    \n",
    "    // Define the DatePickerView\n",
    "    var DatePickerView = widgets.DOMWidgetView.extend({\n",
    "        render: function() {\n",
    "            \n",
    "            // Create the date picker control.\n",
    "            this.$date = $('<input />')\n",
    "                .attr('type', 'date')\n",
    "                .appendTo(this.$el);\n",
    "        },\n",
    "        \n",
    "        update: function() {\n",
    "            \n",
    "            // Set the value of the date control and then call base.\n",
    "            this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
    "            return DatePickerView.__super__.update.apply(this);\n",
    "        },\n",
    "    });\n",
    "    \n",
    "    return {\n",
    "        DatePickerView: DatePickerView\n",
    "    };\n",
    "});"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To get the changed value from the frontend to publish itself to the backend,\n",
    "we need to listen to the change event triggered by the HTM date control and set the value in the model.\n",
    "After the date change event fires and the new value is set in the model,\n",
    "it is very important that we call `this.touch()` to let the widget machinery know which view changed the model.\n",
    "This is important because the widget machinery needs to know which cell to route the message callbacks to.\n",
    "\n",
    "**Final JavaScript code below:**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "requirejs.undef('datepicker');\n",
       "\n",
       "define('datepicker', [\"jupyter-js-widgets\"], function(widgets) {\n",
       "   \n",
       "    // Define the DatePickerView\n",
       "    var DatePickerView = widgets.DOMWidgetView.extend({\n",
       "        render: function() {\n",
       "            \n",
       "            // Create the date picker control.\n",
       "            this.$date = $('<input />')\n",
       "                .attr('type', 'date')\n",
       "                .appendTo(this.$el);\n",
       "        },\n",
       "        \n",
       "        update: function() {\n",
       "            \n",
       "            // Set the value of the date control and then call base.\n",
       "            this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
       "            return DatePickerView.__super__.update.apply(this);\n",
       "        },\n",
       "        \n",
       "        // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
       "        events: {\"change\": \"handle_date_change\"},\n",
       "        \n",
       "        // Callback for when the date is changed.\n",
       "        handle_date_change: function(event) {\n",
       "            this.model.set('value', this.$date.val());\n",
       "            this.touch();\n",
       "        },\n",
       "    });\n",
       "    \n",
       "    return {\n",
       "        DatePickerView: DatePickerView\n",
       "    };\n",
       "});"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%%javascript\n",
    "requirejs.undef('datepicker');\n",
    "\n",
    "define('datepicker', [\"jupyter-js-widgets\"], function(widgets) {\n",
    "   \n",
    "    // Define the DatePickerView\n",
    "    var DatePickerView = widgets.DOMWidgetView.extend({\n",
    "        render: function() {\n",
    "            \n",
    "            // Create the date picker control.\n",
    "            this.$date = $('<input />')\n",
    "                .attr('type', 'date')\n",
    "                .appendTo(this.$el);\n",
    "        },\n",
    "        \n",
    "        update: function() {\n",
    "            \n",
    "            // Set the value of the date control and then call base.\n",
    "            this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
    "            return DatePickerView.__super__.update.apply(this);\n",
    "        },\n",
    "        \n",
    "        // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
    "        events: {\"change\": \"handle_date_change\"},\n",
    "        \n",
    "        // Callback for when the date is changed.\n",
    "        handle_date_change: function(event) {\n",
    "            this.model.set('value', this.$date.val());\n",
    "            this.touch();\n",
    "        },\n",
    "    });\n",
    "    \n",
    "    return {\n",
    "        DatePickerView: DatePickerView\n",
    "    };\n",
    "});"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Test"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To test, create the widget the same way that the other widgets are created."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/html": [
       "<img src= class=\"jupyter-widget\">\n",
       "<script type=\"application/vnd.jupyter-embedded-widgets\">[{},{\"_view_name\":\"DatePickerView\",\"_view_module\":\"datepicker\",\"layout\":\"IPY_MODEL_9e305fda52304dc5b84b71352b542cb8\",\"_model_name\":\"DOMWidgetModel\",\"value\":\"1998-12-01\"}]</script>"
      ]
     },
     "metadata": {
      "isWidgetSnapshot": true
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "my_widget = DateWidget()\n",
    "display(my_widget)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Display the widget again to make sure that both views remain in sync."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA9oAAAAlCAYAAAC9O5EWAAAD+UlEQVR4Xu3ZsZHiQBAFUMng6hzMdeRiYFCEQwokQBSEQCgEg00MWxh7tySw0pZmqmf6rT0adb8v57Pj4I8AAQIECBAgQIAAAQIECBBYTWBc7SYXESBAgAABAgQIECBAgAABAoOi7SMgQIAAAQIECBAgQIAAAQIrCijaK2K6igABAgQIECBAgAABAgQIKNq+AQIECBAgQIAAAQIECBAgsKKAor0ipqsIECBAgAABAgQIECBAgMB4vV6/Ho8HCQJFBC6Xy7Df7/2gU0TXpQQIECBAgAABAgQIRBQYz+fz1263G5TtiPG0PdN3yd5ut8M0TYp221GangABAgQIECBAgACBBQLvov19/na7LXjMUQI/Czyfz/chRftnKycIECBAgAABAgQIEOhHQNHuJ8twmyja4SIxEAECBAgQIECAAAECFQQU7QrIWV+haGdN3t4ECBAgQIAAAQIEcgso2rnzL7q9ol2U1+UECBAgQIAAAQIECAQVULSDBtPDWIp2DynagQABAgQIECBAgACBpQKK9lIx52cLKNqzqRwkQIAAAQIECBAgQKAjAUW7ozCjraJoR0vEPAQIECBAgAABAgQI1BBQtGsoJ32Hop00eGsTIECAAAECBAgQSC6gaCf/AEqur2iX1HU3AQIECBAgQIAAAQJRBRTtqMl0MJei3UGIViBAgAABAgQIECBAYLGAor2YzANzBRTtuVLOESBAgAABAgQIECDQk4Ci3VOawXZRtIMFYhwCBAgQIECAAAECBKoIKNpVmHO+RNHOmbutCRAgQIAAAQIECGQXULSzfwEF91e0C+K6mgABAgQIECBAgACBsAKKdtho2h9M0W4/QxsQIECAAAECBAgQILBcQNFebuaJmQKK9kwoxwgQIECAAAECBAgQ6EpA0e4qzljLKNqx8jANAQIECBAgQIAAAQJ1BBTtOs4p36Jop4zd0gQIECBAgAABAgTSCyja6T+BcgCKdjlbNxMgQIAAAQIECBAgEFdA0Y6bTfOTKdrNR2gBAgQIECBAgAABAgR+IaBo/wLNI/MEFO15Tk4RIECAAAECBAgQINCXgKLdV56htlG0Q8VhGAIECBAgQIAAAQIEKgm8i/bpdBoOh0OlV3pNFoHNZjO8Xq9hmqYxy872JECAAAECBAgQIECAwHi/3z+Px+MfFARKCPwv258fHx9/S9ztTgIECBAgQIAAAQIECEQU8J/GiKmYiQABAgQIECBAgAABAgSaFVC0m43O4AQIECBAgAABAgQIECAQUUDRjpiKmQgQIECAAAECBAgQIECgWQFFu9noDE6AAAECBAgQIECAAAECEQUU7YipmIkAAQIECBAgQIAAAQIEmhX4BxvutCacc2qfAAAAAElFTkSuQmCC",
      "text/html": [
       "<img src= class=\"jupyter-widget\">\n",
       "<script type=\"application/vnd.jupyter-embedded-widgets\">[{},{\"_view_name\":\"DatePickerView\",\"_view_module\":\"datepicker\",\"layout\":\"IPY_MODEL_9e305fda52304dc5b84b71352b542cb8\",\"_model_name\":\"DOMWidgetModel\",\"value\":\"1998-12-01\"}]</script>"
      ]
     },
     "metadata": {
      "isWidgetSnapshot": true
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "my_widget"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Read the date from Python"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "''"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_widget.value"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Set the date from Python"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "my_widget.value = \"1998-12-01\" # December 1st, 1998"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Section 3 - Extra credit"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The 3rd party `dateutil` library is required to continue.  https://pypi.python.org/pypi/python-dateutil"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Import the dateutil library to parse date strings.\n",
    "from dateutil import parser"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the last section we created a fully working date picker widget.\n",
    "Now we will add custom validation and support for labels.\n",
    "So far, only the ISO date format \"YYYY-MM-DD\" is supported.\n",
    "Now, we will add support for all of the date formats recognized by the Python dateutil library."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Python"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The standard property name used for widget labels is `description`.\n",
    "In the code block below, `description` has been added to the Python widget."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "class DateWidget(widgets.DOMWidget):\n",
    "    _view_name = Unicode('DatePickerView').tag(sync=True)\n",
    "    _view_module = Unicode('datepicker').tag(sync=True)\n",
    "    value = Unicode().tag(sync=True)\n",
    "    description = Unicode().tag(sync=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The traitlet machinery searches the class that the trait is defined in for methods with \"`_changed`\" suffixed onto their names.  Any method with the format \"`_X_changed`\" will be called when \"`X`\" is modified.\n",
    "We can take advantage of this to perform validation and parsing of different date string formats.\n",
    "Below, a method that listens to value has been added to the DateWidget."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "class DateWidget(widgets.DOMWidget):\n",
    "    _view_name = Unicode('DatePickerView').tag(sync=True)\n",
    "    _view_module = Unicode('datepicker').tag(sync=True)\n",
    "    value = Unicode().tag(sync=True)\n",
    "    description = Unicode().tag(sync=True)\n",
    "\n",
    "    # This function automatically gets called by the traitlet machinery when\n",
    "    # value is modified because of this function's name.\n",
    "    def _value_changed(self, name, old_value, new_value):\n",
    "        pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now the function parses the date string,\n",
    "and only sets the value in the correct format."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "class DateWidget(widgets.DOMWidget):\n",
    "    _view_name = Unicode('DatePickerView').tag(sync=True)\n",
    "    _view_module = Unicode('datepicker').tag(sync=True)\n",
    "    value = Unicode().tag(sync=True)\n",
    "    description = Unicode().tag(sync=True)\n",
    "    \n",
    "    # This function automatically gets called by the traitlet machinery when\n",
    "    # value is modified because of this function's name.\n",
    "    def _value_changed(self, name, old_value, new_value):\n",
    "        \n",
    "        # Parse the date time value.\n",
    "        try:\n",
    "            parsed_date = parser.parse(new_value)\n",
    "            parsed_date_string = parsed_date.strftime(\"%Y-%m-%d\")\n",
    "        except:\n",
    "            parsed_date_string = ''\n",
    "        \n",
    "        # Set the parsed date string if the current date string is different.\n",
    "        if self.value != parsed_date_string:\n",
    "            self.value = parsed_date_string"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, a `CallbackDispatcher` is added so the user can perform custom validation.\n",
    "If any one of the callbacks registered with the dispatcher returns False,\n",
    "the new date is not set.\n",
    "\n",
    "**Final Python code below:**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "class DateWidget(widgets.DOMWidget):\n",
    "    _view_name = Unicode('DatePickerView').tag(sync=True)\n",
    "    _view_module = Unicode('datepicker').tag(sync=True)\n",
    "    value = Unicode().tag(sync=True)\n",
    "    description = Unicode().tag(sync=True)\n",
    "    \n",
    "    def __init__(self, **kwargs):\n",
    "        super(DateWidget, self).__init__(**kwargs)\n",
    "        \n",
    "        self.validate = widgets.CallbackDispatcher()\n",
    "    \n",
    "    # This function automatically gets called by the traitlet machinery when\n",
    "    # value is modified because of this function's name.\n",
    "    def _value_changed(self, name, old_value, new_value):\n",
    "        \n",
    "        # Parse the date time value.\n",
    "        try:\n",
    "            parsed_date = parser.parse(new_value)\n",
    "            parsed_date_string = parsed_date.strftime(\"%Y-%m-%d\")\n",
    "        except:\n",
    "            parsed_date_string = ''\n",
    "        \n",
    "        # Set the parsed date string if the current date string is different.\n",
    "        if old_value != new_value:\n",
    "            valid = self.validate(parsed_date)\n",
    "            if valid in (None, True):\n",
    "                self.value = parsed_date_string\n",
    "            else:\n",
    "                self.value = old_value\n",
    "                self.send_state() # The traitlet event won't fire since the value isn't changing.\n",
    "                                  # We need to force the back-end to send the front-end the state\n",
    "                                  # to make sure that the date control date doesn't change."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## JavaScript"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using the Javascript code from the last section,\n",
    "we add a label to the date time object.\n",
    "The label is a div with the `widget-hlabel` class applied to it.\n",
    "`widget-hlabel` is a class provided by the widget framework that applies special styling to a div to make it look like the rest of the horizontal labels used with the built-in widgets.\n",
    "Similar to the `widget-hlabel` class is the `widget-hbox-single` class.\n",
    "The `widget-hbox-single` class applies special styling to widget containers that store a single line horizontal widget.\n",
    "\n",
    "We hide the label if the description value is blank."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "application/javascript": [
       "requirejs.undef('datepicker');\n",
       "\n",
       "define('datepicker', [\"jupyter-js-widgets\"], function(widgets) {\n",
       "    \n",
       "    // Define the DatePickerView\n",
       "    var DatePickerView = widgets.DOMWidgetView.extend({\n",
       "        render: function() {\n",
       "            this.$el.addClass('widget-hbox-single'); /* Apply this class to the widget container to make\n",
       "                                                        it fit with the other built in widgets.*/\n",
       "            // Create a label.\n",
       "            this.$label = $('<div />')\n",
       "                .addClass('widget-hlabel')\n",
       "                .appendTo(this.$el)\n",
       "                .hide(); // Hide the label by default.\n",
       "            \n",
       "            // Create the date picker control.\n",
       "            this.$date = $('<input />')\n",
       "                .attr('type', 'date')\n",
       "                .appendTo(this.$el);\n",
       "        },\n",
       "        \n",
       "        update: function() {\n",
       "            \n",
       "            // Set the value of the date control and then call base.\n",
       "            this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
       "            \n",
       "            // Hide or show the label depending on the existance of a description.\n",
       "            var description = this.model.get('description');\n",
       "            if (description == undefined || description == '') {\n",
       "                this.$label.hide();\n",
       "            } else {\n",
       "                this.$label.show();\n",
       "                this.$label.text(description);\n",
       "            }\n",
       "            \n",
       "            return DatePickerView.__super__.update.apply(this);\n",
       "        },\n",
       "        \n",
       "        // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
       "        events: {\"change\": \"handle_date_change\"},\n",
       "        \n",
       "        // Callback for when the date is changed.\n",
       "        handle_date_change: function(event) {\n",
       "            this.model.set('value', this.$date.val());\n",
       "            this.touch();\n",
       "        },\n",
       "    });\n",
       "    \n",
       "    return {\n",
       "        DatePickerView: DatePickerView\n",
       "    };\n",
       "});"
      ],
      "text/plain": [
       "<IPython.core.display.Javascript object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "%%javascript\n",
    "requirejs.undef('datepicker');\n",
    "\n",
    "define('datepicker', [\"jupyter-js-widgets\"], function(widgets) {\n",
    "    \n",
    "    // Define the DatePickerView\n",
    "    var DatePickerView = widgets.DOMWidgetView.extend({\n",
    "        render: function() {\n",
    "            this.$el.addClass('widget-hbox-single'); /* Apply this class to the widget container to make\n",
    "                                                        it fit with the other built in widgets.*/\n",
    "            // Create a label.\n",
    "            this.$label = $('<div />')\n",
    "                .addClass('widget-hlabel')\n",
    "                .appendTo(this.$el)\n",
    "                .hide(); // Hide the label by default.\n",
    "            \n",
    "            // Create the date picker control.\n",
    "            this.$date = $('<input />')\n",
    "                .attr('type', 'date')\n",
    "                .appendTo(this.$el);\n",
    "        },\n",
    "        \n",
    "        update: function() {\n",
    "            \n",
    "            // Set the value of the date control and then call base.\n",
    "            this.$date.val(this.model.get('value')); // ISO format \"YYYY-MM-DDTHH:mm:ss.sssZ\" is required\n",
    "            \n",
    "            // Hide or show the label depending on the existance of a description.\n",
    "            var description = this.model.get('description');\n",
    "            if (description == undefined || description == '') {\n",
    "                this.$label.hide();\n",
    "            } else {\n",
    "                this.$label.show();\n",
    "                this.$label.text(description);\n",
    "            }\n",
    "            \n",
    "            return DatePickerView.__super__.update.apply(this);\n",
    "        },\n",
    "        \n",
    "        // Tell Backbone to listen to the change event of input controls (which the HTML date picker is)\n",
    "        events: {\"change\": \"handle_date_change\"},\n",
    "        \n",
    "        // Callback for when the date is changed.\n",
    "        handle_date_change: function(event) {\n",
    "            this.model.set('value', this.$date.val());\n",
    "            this.touch();\n",
    "        },\n",
    "    });\n",
    "    \n",
    "    return {\n",
    "        DatePickerView: DatePickerView\n",
    "    };\n",
    "});"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Test"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To test the drawing of the label we create the widget like normal but supply the additional description property a value."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/html": [
       "<img src= class=\"jupyter-widget\">\n",
       "<script type=\"application/vnd.jupyter-embedded-widgets\">[{},{\"layout\":\"IPY_MODEL_e0a090064abd4f63968a61444733633f\",\"description\":\"First:\"},{},{\"layout\":\"IPY_MODEL_f71b132c0a3e421997af50c56e5ca783\",\"description\":\"Last:\"},{},{\"_view_name\":\"DatePickerView\",\"_view_module\":\"datepicker\",\"layout\":\"IPY_MODEL_e5ba933f7f304b5faf6fe3c0f4e22a42\",\"description\":\"DOB:\",\"_model_name\":\"DOMWidgetModel\",\"value\":\"\"}]</script>"
      ]
     },
     "metadata": {
      "isWidgetSnapshot": true
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Add some additional widgets for aesthetic purpose\n",
    "display(widgets.Text(description=\"First:\"))\n",
    "display(widgets.Text(description=\"Last:\"))\n",
    "\n",
    "my_widget = DateWidget()\n",
    "display(my_widget)\n",
    "my_widget.description=\"DOB:\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we will try to create a widget that only accepts dates in the year 2014.  We render the widget without a description to verify that it can still render without a label."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/html": [
       "<img src= class=\"jupyter-widget\">\n",
       "<script type=\"application/vnd.jupyter-embedded-widgets\">[{},{\"_view_name\":\"DatePickerView\",\"_view_module\":\"datepicker\",\"layout\":\"IPY_MODEL_3dc81d965b5c4efe95dc6e97843eddec\",\"description\":\"\",\"_model_name\":\"DOMWidgetModel\",\"value\":\"2014-12-02\"}]</script>"
      ]
     },
     "metadata": {
      "isWidgetSnapshot": true
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "my_widget = DateWidget()\n",
    "display(my_widget)\n",
    "\n",
    "def require_2014(date):\n",
    "    return not date is None and date.year == 2014\n",
    "my_widget.validate.register_callback(require_2014)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Try setting a valid date\n",
    "my_widget.value = \"December 2, 2014\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# Try setting an invalid date\n",
    "my_widget.value = \"June 12, 1990\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'2014-12-02'"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "my_widget.value"
   ]
  }
 ],
 "metadata": {
  "cell_tags": [
   [
    "<None>",
    null
   ]
  ],
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.4.3+"
  },
  "widgets": {
   "state": {
    "29402bd1313840429af795d1fa574df7": {
     "views": [
      {
       "cell": {
        "cell_type": "code",
        "execution_count": 10,
        "metadata": {
         "collapsed": false,
         "trusted": true
        },
        "outputs": [
         {
          "data": {
           "image/png": "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",
           "text/html": "<img src= class=\"jupyter-widget\">\n<script type=\"application/vnd.jupyter-embedded-widgets\">[{},{\"_view_name\":\"DatePickerView\",\"_view_module\":\"datepicker\",\"layout\":\"IPY_MODEL_9e305fda52304dc5b84b71352b542cb8\",\"_model_name\":\"DOMWidgetModel\",\"value\":\"1998-12-01\"}]</script>"
          },
          "metadata": {
           "isWidgetSnapshot": true
          },
          "output_type": "display_data"
         }
        ],
        "source": "my_widget = DateWidget()\ndisplay(my_widget)"
       },
       "cell_index": 30,
       "root": true
      },
      {
       "cell": {
        "cell_type": "code",
        "execution_count": 11,
        "metadata": {
         "collapsed": false,
         "trusted": true
        },
        "outputs": [
         {
          "data": {
           "image/png": "iVBORw0KGgoAAAANSUhEUgAAA9oAAAAlCAYAAAC9O5EWAAAD+UlEQVR4Xu3ZsZHiQBAFUMng6hzMdeRiYFCEQwokQBSEQCgEg00MWxh7tySw0pZmqmf6rT0adb8v57Pj4I8AAQIECBAgQIAAAQIECBBYTWBc7SYXESBAgAABAgQIECBAgAABAoOi7SMgQIAAAQIECBAgQIAAAQIrCijaK2K6igABAgQIECBAgAABAgQIKNq+AQIECBAgQIAAAQIECBAgsKKAor0ipqsIECBAgAABAgQIECBAgMB4vV6/Ho8HCQJFBC6Xy7Df7/2gU0TXpQQIECBAgAABAgQIRBQYz+fz1263G5TtiPG0PdN3yd5ut8M0TYp221GangABAgQIECBAgACBBQLvov19/na7LXjMUQI/Czyfz/chRftnKycIECBAgAABAgQIEOhHQNHuJ8twmyja4SIxEAECBAgQIECAAAECFQQU7QrIWV+haGdN3t4ECBAgQIAAAQIEcgso2rnzL7q9ol2U1+UECBAgQIAAAQIECAQVULSDBtPDWIp2DynagQABAgQIECBAgACBpQKK9lIx52cLKNqzqRwkQIAAAQIECBAgQKAjAUW7ozCjraJoR0vEPAQIECBAgAABAgQI1BBQtGsoJ32Hop00eGsTIECAAAECBAgQSC6gaCf/AEqur2iX1HU3AQIECBAgQIAAAQJRBRTtqMl0MJei3UGIViBAgAABAgQIECBAYLGAor2YzANzBRTtuVLOESBAgAABAgQIECDQk4Ci3VOawXZRtIMFYhwCBAgQIECAAAECBKoIKNpVmHO+RNHOmbutCRAgQIAAAQIECGQXULSzfwEF91e0C+K6mgABAgQIECBAgACBsAKKdtho2h9M0W4/QxsQIECAAAECBAgQILBcQNFebuaJmQKK9kwoxwgQIECAAAECBAgQ6EpA0e4qzljLKNqx8jANAQIECBAgQIAAAQJ1BBTtOs4p36Jop4zd0gQIECBAgAABAgTSCyja6T+BcgCKdjlbNxMgQIAAAQIECBAgEFdA0Y6bTfOTKdrNR2gBAgQIECBAgAABAgR+IaBo/wLNI/MEFO15Tk4RIECAAAECBAgQINCXgKLdV56htlG0Q8VhGAIECBAgQIAAAQIEKgm8i/bpdBoOh0OlV3pNFoHNZjO8Xq9hmqYxy872JECAAAECBAgQIECAwHi/3z+Px+MfFARKCPwv258fHx9/S9ztTgIECBAgQIAAAQIECEQU8J/GiKmYiQABAgQIECBAgAABAgSaFVC0m43O4AQIECBAgAABAgQIECAQUUDRjpiKmQgQIECAAAECBAgQIECgWQFFu9noDE6AAAECBAgQIECAAAECEQUU7YipmIkAAQIECBAgQIAAAQIEmhX4BxvutCacc2qfAAAAAElFTkSuQmCC",
           "text/html": "<img src= class=\"jupyter-widget\">\n<script type=\"application/vnd.jupyter-embedded-widgets\">[{},{\"_view_name\":\"DatePickerView\",\"_view_module\":\"datepicker\",\"layout\":\"IPY_MODEL_9e305fda52304dc5b84b71352b542cb8\",\"_model_name\":\"DOMWidgetModel\",\"value\":\"1998-12-01\"}]</script>"
          },
          "metadata": {
           "isWidgetSnapshot": true
          },
          "output_type": "display_data"
         }
        ],
        "source": "my_widget"
       },
       "cell_index": 32,
       "root": true
      }
     ]
    },
    "3dc81d965b5c4efe95dc6e97843eddec": {
     "views": []
    },
    "63fd4d6d070148018e4867d75a442324": {
     "views": []
    },
    "7362709c6f7940cbbced6487363291fa": {
     "views": [
      {
       "cell": {
        "cell_type": "code",
        "execution_count": 20,
        "metadata": {
         "collapsed": false,
         "trusted": true
        },
        "outputs": [
         {
          "data": {
           "image/png": "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",
           "text/html": "<img src= class=\"jupyter-widget\">\n<script type=\"application/vnd.jupyter-embedded-widgets\">[{},{\"layout\":\"IPY_MODEL_e0a090064abd4f63968a61444733633f\",\"description\":\"First:\"},{},{\"layout\":\"IPY_MODEL_f71b132c0a3e421997af50c56e5ca783\",\"description\":\"Last:\"},{},{\"_view_name\":\"DatePickerView\",\"_view_module\":\"datepicker\",\"layout\":\"IPY_MODEL_e5ba933f7f304b5faf6fe3c0f4e22a42\",\"description\":\"DOB:\",\"_model_name\":\"DOMWidgetModel\",\"value\":\"\"}]</script>"
          },
          "metadata": {
           "isWidgetSnapshot": true
          },
          "output_type": "display_data"
         }
        ],
        "source": "# Add some additional widgets for aesthetic purpose\ndisplay(widgets.Text(description=\"First:\"))\ndisplay(widgets.Text(description=\"Last:\"))\n\nmy_widget = DateWidget()\ndisplay(my_widget)\nmy_widget.description=\"DOB:\""
       },
       "cell_index": 55,
       "root": true
      }
     ]
    },
    "9e305fda52304dc5b84b71352b542cb8": {
     "views": []
    },
    "b2205857d4da402fa67be8f067af2a77": {
     "views": [
      {
       "cell": {
        "cell_type": "code",
        "execution_count": 5,
        "metadata": {
         "collapsed": false,
         "trusted": true
        },
        "outputs": [
         {
          "data": {
           "image/png": "iVBORw0KGgoAAAANSUhEUgAAA9oAAAAfCAYAAAAY2rXdAAAHP0lEQVR4Xu3deah0ZQEGcA3SyAwzwjAjF9R2SXNDhE9QhFJTsNIWQ03TTMoltbL6BBXR0gpThCLLAsXMQFIoxcQWIRNxQ8j8Q0UDobLFBdfngXNgGLxznY/z3/0deJg5d+acmfu7889z3/e8s/FGNgIECBAgQIAAAQIECBAgQGAygY0nO5MTESBAgAABAgQIECBAgAABAhsp2j4EBAgQIECAAAECBAgQIEBgQgFFe0JMpyJAgAABAgQIECBAgAABAoq2zwABAgQIECBAgAABAgQIEJhQQNGeENOpCBAgQIAAAQIECBAgQICAou0zQIAAAQIECBAgQIAAAQIEJhRQtCfEdCoCBAgQIECAAAECBAgQIKBo+wwQIECAAAECBAgQIECAAIEJBaYo2lvk/ZyW7J/snczvT/h2JzvVjjnT2cl/kpPnzvrW7H812Tk5bLJXdCICBAgQIECAAAECBAgQWBMCLdr7JhckeyRfSq5Onk8+kVyW/C1pkb55BZFN8/Njki8n707m95eFPDQH/CR5Kjk8eTK5NDkouSRZn7Qg7zU874bcfit5dokXemOe++PhNU6YO27L7H8j2SXpPw+6fXPY7/uxESBAgAABAgQIECBAgACBFQXGEe1T84wW5XfNPfOe7P86aZFdtB2cBy9KWrS7ze8v+yfouT6W7DQcuHVuH01a/q+bOdmVuX908vKyL5DnfzfZLJkv2j3V8cNrjUW7/3x4/5ANeCmHECBAgAABAgQIECBAgMBaERiL9lfyCzfbzv3id2e/RXv9KiAdbf5OMhbt+f1lPXfLAXcOxfb+4eDf5/bvybHDfqd4n5J0CviGbH2/b0perWh/Pj8/IhmL9vdz/30z+xvyeo4hQIAAAQIECBAgQIAAgTUgsGzR3jUmHa1u6Xx90tHkfyerFe2OBh+XPJ3smZyRtEgv2h7Kg1cl5wxPuje3Hdl+e9Kp7S3D/UfAeJ5eG97S/czwGj/P7c+SDyVfTzoF/gPJtsPtfNH+aH7+kaRT1vdL/p+MRfvM3O/vfNQq79nDBAgQIECAAAECBAgQILDGBWaLdgvt5XMeLdL92fqko7+9/9nhOX/M7R1Jr99eVLQ7PbtluNeA/zfpdc4/THZI/rfA//w8dkjSkt6C/MnkrKRF/6bhvZw4c/z1uf+D5NbkHUmL+rqk099/mbwl6bXkvbb7ymS2aHfKfEfuP5y8mFwxvL+xaLdgt2i3cNsIECBAgAABAgQIECBAgMCKAsuMaH88Z+kocktutxbgfyVdoXtR0f50Hu/K3i243V6XdIGzTvvuiPNKWxcj64j1e5KW7B8lXSTtsaTXlLf0fm04eJvcPpJ0kbNxUbQW538mLddd+OwfSRc5G7fZot3rtWvR83abnzrewt2i3SnkNgIECBAgQIAAAQIECBAgsKLAMkW7I9cdhf7iq5xtUdFen+d3FLrXXY/bX3PnV8l5q/xtHszjv0jemXSBsl6f3YXSOvW8127/eTh+XW47kv3mpKPm3VqeP5gckLSkt2jPXs89W7R/l8f+lHx7OHa+aL83P2/RvnaV9+thAgQIECBAgAABAgQIEFjjAssU7U/Fql8D1u+gfm5w6yh1p48vKtodUb44eVvSa6u73ZV0anindC/aOp29i5W1kHdaeL96q4W512t3mve42vj2ud+F0jo9/S/DCfuamyT9yrLVinZXMu+U8a5q3m2+aHfafEfNW/xtBAgQIECAAAECBAgQIEBgRYGxaJ+eZ3TV8ZbJ2e2B7LSE9nukW3JbZnu9dUeVe13zC0mnc3fEuiPEOw8Hz+53lPnh5KTkmqSLlnX0uCPcXbhs0daR5Jbqjmg/Pjzxxtx2YbN+Hdns9tvh/Y3Xbd+W/U5Z7zXaLdqdrj5ONe9xHfFugf5C0hXGO4193fDeWuy7ONruSf85cGCy1fCcRe/XYwQIECBAgAABAgQIECCwxgVatPdJLkw6Ot3y2pW+Wy57XXQXBesU7V6HfXOyb9KFzFp8f5r0mubNk+8lLatd6OwPc/u/Gc7dYtuC/Yaki6q1xL+W7bI8aXa6+uey3+J++9zBXY2812I/kXQl9C7W1gXSOn2834P9UtJFzTqavl3SaeB9L0cm9yXj6HlH6HsdeK8NPze5ZXis0+Y/81resOcQIECAAAECBAgQIECAwNoVGEe0166A35wAAQIECBAgQIAAAQIECEwooGhPiOlUBAgQIECAAAECBAgQIEBA0fYZIECAAAECBAgQIECAAAECEwoo2hNiOhUBAgQIECBAgAABAgQIEFC0fQYIECBAgAABAgQIECBAgMCEAor2hJhORYAAAQIECBAgQIAAAQIEFG2fAQIECBAgQIAAAQIECBAgMKGAoj0hplMRIECAAAECBAgQIECAAAFF22eAAAECBAgQIECAAAECBAhMKKBoT4jpVAQIECBAgAABAgQIECBAQNH2GSBAgAABAgQIECBAgAABAhMKvAKSwfMgNi4bSAAAAABJRU5ErkJggg==",
           "text/html": "<img src= class=\"jupyter-widget\">\n<script type=\"application/vnd.jupyter-embedded-widgets\">[{},{\"_view_name\":\"DatePickerView\",\"_view_module\":\"datepicker\",\"layout\":\"IPY_MODEL_63fd4d6d070148018e4867d75a442324\",\"_model_name\":\"DOMWidgetModel\"}]</script>"
          },
          "metadata": {
           "isWidgetSnapshot": true
          },
          "output_type": "display_data"
         }
        ],
        "source": "DateWidget()"
       },
       "cell_index": 16,
       "root": true
      }
     ]
    },
    "e01268114d2f4c968757e46320ae1370": {
     "views": [
      {
       "cell": {
        "cell_type": "code",
        "execution_count": 20,
        "metadata": {
         "collapsed": false,
         "trusted": true
        },
        "outputs": [
         {
          "data": {
           "image/png": "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",
           "text/html": "<img src= class=\"jupyter-widget\">\n<script type=\"application/vnd.jupyter-embedded-widgets\">[{},{\"layout\":\"IPY_MODEL_e0a090064abd4f63968a61444733633f\",\"description\":\"First:\"},{},{\"layout\":\"IPY_MODEL_f71b132c0a3e421997af50c56e5ca783\",\"description\":\"Last:\"},{},{\"_view_name\":\"DatePickerView\",\"_view_module\":\"datepicker\",\"layout\":\"IPY_MODEL_e5ba933f7f304b5faf6fe3c0f4e22a42\",\"description\":\"DOB:\",\"_model_name\":\"DOMWidgetModel\",\"value\":\"\"}]</script>"
          },
          "metadata": {
           "isWidgetSnapshot": true
          },
          "output_type": "display_data"
         }
        ],
        "source": "# Add some additional widgets for aesthetic purpose\ndisplay(widgets.Text(description=\"First:\"))\ndisplay(widgets.Text(description=\"Last:\"))\n\nmy_widget = DateWidget()\ndisplay(my_widget)\nmy_widget.description=\"DOB:\""
       },
       "cell_index": 55,
       "root": true
      }
     ]
    },
    "e03a08aacab14aa39777928fbd86e9f6": {
     "views": [
      {
       "cell": {
        "cell_type": "code",
        "execution_count": 20,
        "metadata": {
         "collapsed": false,
         "trusted": true
        },
        "outputs": [
         {
          "data": {
           "image/png": "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",
           "text/html": "<img src= class=\"jupyter-widget\">\n<script type=\"application/vnd.jupyter-embedded-widgets\">[{},{\"layout\":\"IPY_MODEL_e0a090064abd4f63968a61444733633f\",\"description\":\"First:\"},{},{\"layout\":\"IPY_MODEL_f71b132c0a3e421997af50c56e5ca783\",\"description\":\"Last:\"},{},{\"_view_name\":\"DatePickerView\",\"_view_module\":\"datepicker\",\"layout\":\"IPY_MODEL_e5ba933f7f304b5faf6fe3c0f4e22a42\",\"description\":\"DOB:\",\"_model_name\":\"DOMWidgetModel\",\"value\":\"\"}]</script>"
          },
          "metadata": {
           "isWidgetSnapshot": true
          },
          "output_type": "display_data"
         }
        ],
        "source": "# Add some additional widgets for aesthetic purpose\ndisplay(widgets.Text(description=\"First:\"))\ndisplay(widgets.Text(description=\"Last:\"))\n\nmy_widget = DateWidget()\ndisplay(my_widget)\nmy_widget.description=\"DOB:\""
       },
       "cell_index": 55,
       "root": true
      }
     ]
    },
    "e0a090064abd4f63968a61444733633f": {
     "views": []
    },
    "e5ba933f7f304b5faf6fe3c0f4e22a42": {
     "views": []
    },
    "f71b132c0a3e421997af50c56e5ca783": {
     "views": []
    },
    "fef11ed5103f4a34bc370206228ed87b": {
     "views": [
      {
       "cell": {
        "cell_type": "code",
        "execution_count": 21,
        "metadata": {
         "collapsed": false,
         "trusted": true
        },
        "outputs": [
         {
          "data": {
           "image/png": "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",
           "text/html": "<img src= class=\"jupyter-widget\">\n<script type=\"application/vnd.jupyter-embedded-widgets\">[{},{\"_view_name\":\"DatePickerView\",\"_view_module\":\"datepicker\",\"layout\":\"IPY_MODEL_3dc81d965b5c4efe95dc6e97843eddec\",\"description\":\"\",\"_model_name\":\"DOMWidgetModel\",\"value\":\"2014-12-02\"}]</script>"
          },
          "metadata": {
           "isWidgetSnapshot": true
          },
          "output_type": "display_data"
         }
        ],
        "source": "my_widget = DateWidget()\ndisplay(my_widget)\n\ndef require_2014(date):\n    return not date is None and date.year == 2014\nmy_widget.validate.register_callback(require_2014)"
       },
       "cell_index": 57,
       "root": true
      }
     ]
    }
   },
   "version": "0.0.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
